/******************************************************************************/
/* Include Files                                                              */
/******************************************************************************/
#include "stdio.h"
#include "stdint.h"
#include "osObjects.h"                      // RTOS object definitions
#include "Driver_USART.h"
#include "Driver_SPI.h"
#include "Driver_I2C.h"

#include "Communication.h"

#include "Driver_SPI.h"
#include "hal.h"

#define SPI_DRV_NUM           FLASH_SPI_DRV_NUM
#define _SPI_Driver_(n)  Driver_SPI##n
#define  SPI_Driver_(n) _SPI_Driver_(n)

extern ARM_DRIVER_SPI  SPI_Driver_(SPI_DRV_NUM);
#define pDriver_SPI       (&SPI_Driver_(SPI_DRV_NUM))

//extern   ARM_DRIVER_SPI         Driver_SPI2;
//#define  pDriver_SPI               (&Driver_SPI2)


// The following example code shows the usage of the I2C interface in Master mode.
#include "Driver_I2C.h"

#define EEPROM_I2C_ADDR       0xa0 //51      /* EEPROM I2C address */
#define POOLING_TRUE 1

/* I2C driver instance */
extern ARM_DRIVER_I2C            Driver_I2C1;
#define  pDriver_I2C               (&Driver_I2C1)

static volatile uint32_t I2C_Event;

/* I2C Signal Event function callback */
void I2C_SignalEvent(uint32_t event)
{

    /* Save received events */
    I2C_Event |= event;

    /* Optionally, user can define specific actions for an event */

    if (event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE)
    {
        /* Less data was transferred than requested */
    }

    if (event & ARM_I2C_EVENT_TRANSFER_DONE)
    {
        /* Transfer or receive is finished */
    }

    if (event & ARM_I2C_EVENT_ADDRESS_NACK)
    {
        /* Slave address was not acknowledged */
    }

    if (event & ARM_I2C_EVENT_ARBITRATION_LOST)
    {
        /* Master lost bus arbitration */
    }

    if (event & ARM_I2C_EVENT_BUS_ERROR)
    {
        /* Invalid start/stop position detected */
    }

    if (event & ARM_I2C_EVENT_BUS_CLEAR)
    {
        /* Bus clear operation completed */
    }

    if (event & ARM_I2C_EVENT_GENERAL_CALL)
    {
        /* Slave was addressed with a general call address */
    }

    if (event & ARM_I2C_EVENT_SLAVE_RECEIVE)
    {
        /* Slave addressed as receiver but SlaveReceive operation is not started */
    }

    if (event & ARM_I2C_EVENT_SLAVE_TRANSMIT)
    {
        /* Slave addressed as transmitter but SlaveTransmit operation is not started */
    }
}
/* Read I2C connected EEPROM (event driven example) */
int32_t EEPROM_Read_Event(uint16_t addr, uint8_t* buf, uint32_t len)
{
    uint8_t a[2];

    a[0] = (uint8_t)(addr >> 8);
    a[1] = (uint8_t)(addr & 0xFF);
    /* Clear event flags before new transfer */
    I2C_Event = 0U;

    pDriver_I2C->MasterTransmit(EEPROM_I2C_ADDR, a, 2, true);

    /* Wait until transfer completed */
    while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
    /* Check if all data transferred */
    if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U)
    {
        return -1;
    }

    /* Clear event flags before new transfer */
    I2C_Event = 0U;

    pDriver_I2C->MasterReceive(EEPROM_I2C_ADDR, buf, len, false);

    /* Wait until transfer completed */
    while ((I2C_Event & ARM_I2C_EVENT_TRANSFER_DONE) == 0U);
    /* Check if all data transferred */
    if ((I2C_Event & ARM_I2C_EVENT_TRANSFER_INCOMPLETE) != 0U)
    {
        return -1;
    }

    return 0;
}
/* Read I2C connected EEPROM (pooling example) */
int32_t EEPROM_Read_Pool(uint16_t addr, uint8_t* buf, uint32_t len)
{
    uint8_t a[2];

    a[0] = (uint8_t)(addr >> 8);
    a[1] = (uint8_t)(addr & 0xFF);

    pDriver_I2C->MasterTransmit(EEPROM_I2C_ADDR, a, 2, true);

    /* Wait until transfer completed */
    while (pDriver_I2C->GetStatus().busy);
    /* Check if all data transferred */
    if (pDriver_I2C->GetDataCount() != len)
    {
        return -1;
    }

    pDriver_I2C->MasterReceive(EEPROM_I2C_ADDR, buf, len, false);

    /* Wait until transfer completed */
    while (pDriver_I2C->GetStatus().busy);
    /* Check if all data transferred */
    if (pDriver_I2C->GetDataCount() != len)
    {
        return -1;
    }

    return 0;
}
/* Write I2C connected EEPROM (pooling example) */
int32_t EEPROM_Write_Pool(uint16_t addr, uint8_t* buf, uint32_t len)
{
    uint8_t a[2];

    a[0] = (uint8_t)(addr >> 8);
    a[1] = (uint8_t)(addr & 0xFF);

    pDriver_I2C->MasterTransmit(EEPROM_I2C_ADDR, a, 2, true);

    /* Wait until transfer completed */
    while (pDriver_I2C->GetStatus().busy);
    /* Check if all data transferred */
    if (pDriver_I2C->GetDataCount() != len)
    {
        return -1;
    }

    pDriver_I2C->MasterReceive(EEPROM_I2C_ADDR, buf, len, false);

    /* Wait until transfer completed */
    while (pDriver_I2C->GetStatus().busy);
    /* Check if all data transferred */
    if (pDriver_I2C->GetDataCount() != len)
    {
        return -1;
    }

    return 0;
}

/* Initialize I2C connected EEPROM */
int32_t EEPROM_Initialize()
{
    int32_t status;
    uint8_t val;
#if POOLING_TRUE

    pDriver_I2C->Initialize(NULL);

#else

    pDriver_I2C->Initialize(I2C_SignalEvent);

#endif
    pDriver_I2C->PowerControl(ARM_POWER_FULL);
    pDriver_I2C->Control(ARM_I2C_BUS_SPEED, ARM_I2C_BUS_SPEED_FAST);
    pDriver_I2C->Control(ARM_I2C_BUS_CLEAR, 0);

    /* Check if EEPROM can be accessed */
#if POOLING_TRUE

        status = EEPROM_Read_Pool(0x00, &val, 1);

#else
 
        status = EEPROM_Read_Event(0x00, &val, 1);
 
#endif

    return (status);
}


/*******************************************************************************
 * @brief Initializes the I2C communication peripheral.
 *
 * @param clockFreq - I2C clock frequency (Hz).
 *                    Example: 100000 - I2C clock frequency is 100 kHz.
 * @return status - Result of the initialization procedure.
 *                  Example: 1 - if initialization was successful;
 *                           0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char I2C_Init(unsigned long clockFreq)
{
    pDriver_I2C->Initialize;
}

/*******************************************************************************
 * @brief Writes data to a slave device.
 *
 * @param slaveAddress - Adress of the slave device.
 * @param dataBuffer - Pointer to a buffer storing the transmission data.
 * @param bytesNumber - Number of bytes to write.
 * @param stopBit - Stop condition control.
 *                  Example: 0 - A stop condition will not be sent;
 *                           1 - A stop condition will be sent.
 *
 * @return status - Number of written bytes.
*******************************************************************************/
unsigned char I2C_Write(unsigned char slaveAddress,
                        unsigned char* dataBuffer,
                        unsigned char bytesNumber,
                        unsigned char stopBit)
{
    // Add your code here.
}

/*******************************************************************************
 * @brief Reads data from a slave device.
 *
 * @param slaveAddress - Adress of the slave device.
 * @param dataBuffer - Pointer to a buffer that will store the received data.
 * @param bytesNumber - Number of bytes to read.
 * @param stopBit - Stop condition control.
 *                  Example: 0 - A stop condition will not be sent;
 *                           1 - A stop condition will be sent.
 *
 * @return status - Number of read bytes.
*******************************************************************************/
unsigned char I2C_Read(unsigned char slaveAddress,
                       unsigned char* dataBuffer,
                       unsigned char bytesNumber,
                       unsigned char stopBit)
{
    // Add your code here.
}
extern osThreadId tid_Thread;
//  callback function registered by the function ARM_SPI_Initialize
static void SPI_SignalEventCB(uint32_t event)
{
    switch (event)
    {
    case ARM_SPI_EVENT_TRANSFER_COMPLETE:
        osSignalSet(tid_Thread, 0x01);
        break;
    case ARM_SPI_EVENT_DATA_LOST:
        break;
    case ARM_SPI_EVENT_MODE_FAULT:
        break;
    default:
        break;

    }
}

/*******************************************************************************
 * @brief Initializes the SPI communication peripheral.
 *
 * @param lsbFirst - Transfer format (0 or 1).
 *                   Example: 0x0 - MSB first.
 *                            0x1 - LSB first.
 * @param clockFreq - SPI clock frequency (Hz).
 *                    Example: 1000 - SPI clock frequency is 1 kHz.
 * @param clockPol - SPI clock polarity (0 or 1).
 *                   Example: 0x0 - Idle state for clock is a low level; active
 *                                  state is a high level;
 *                        0x1 - Idle state for clock is a high level; active
 *                                  state is a low level.
 * @param clockEdg - SPI clock edge (0 or 1).
 *                   Example: 0x0 - Serial output data changes on transition
 *                                  from idle clock state to active clock state;
 *                            0x1 - Serial output data changes on transition
 *                                  from active clock state to idle clock state.
 *
 * @return status - Result of the initialization procedure.
 *                  Example: 1 - if initialization was successful;
 *                           0 - if initialization was unsuccessful.
*******************************************************************************/
unsigned char SPI_Init(unsigned char lsbFirst,
                       unsigned long clockFreq,
                       unsigned char clockPol,
                       unsigned char clockEdg)
{
    int32_t status;

#if 1
    ARM_DRIVER_VERSION   version;
    ARM_SPI_CAPABILITIES drv_capabilities;

    version = pDriver_SPI->GetVersion();
    if (version.api < 0x200) /* requires at minimum API version 2.00 or higher */
    {
        /* error handling                                 */
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return 3;
    }

    drv_capabilities = pDriver_SPI->GetCapabilities();
    if (drv_capabilities.event_mode_fault == 0)
    {
        /* error handling */
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return 4;
    }
#endif



    status = pDriver_SPI->Initialize(SPI_SignalEventCB);
    if (ARM_DRIVER_OK != status)
    {
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return 1;
    }
    status = pDriver_SPI->PowerControl(ARM_POWER_FULL);
    if (ARM_DRIVER_OK != status)
    {
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return 2;
    }

    //ptrSPI->Control(ARM_SPI_MODE_MASTER | ARM_SPI_CPOL1_CPHA1 | ARM_SPI_MSB_LSB | ARM_SPI_SS_MASTER_SW | ARM_SPI_DATA_BITS(8), 10000000);
    // configure: SPI master | clock polarity=1, clock phase=1 | bits per frame=16 | bus speed : 1000000
    status = pDriver_SPI->Control(/*ARM_SPI_SS_MASTER_HW_OUTPUT |*/
                 /*ARM_SPI_SS_MASTER_SW |*/
                 /* ARM_SPI_SS_MASTER_UNUSED */
                 ARM_SPI_MSB_LSB |
                 ARM_SPI_MODE_MASTER   |
                 ARM_SPI_CPOL1_CPHA1   |
                 ARM_SPI_DATA_BITS(8), 2000000);

    if (ARM_DRIVER_OK != status)
    {
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return 3;
    }
    //ptrSPI->Control(ARM_SPI_CONTROL_SS, ARM_SPI_SS_INACTIVE);


    status = pDriver_SPI->Control(ARM_SPI_GET_BUS_SPEED, ARM_SPI_SS_ACTIVE);
    if (status < 0)
    {
        printf("%s %d error %#x!\r\n", __FUNCTION__, __LINE__, status);
    }

    printf("speed %d bps\r\n", status);

    return 0;
}

/*******************************************************************************
 * @brief Reads data from SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer as an input parameter and the
 *               read buffer as an output parameter.
 * @param bytesNumber - Number of bytes to read.
 *
 * @return Number of read bytes.
*******************************************************************************/
unsigned char SPI_Read(unsigned char slaveDeviceId,
                       unsigned char* data,
                       unsigned char bytesNumber)
{
    // int32_t ARM_SPI_Receive  (   void *      data,
    // uint32_t     num
    // )

    // Start receiving data from SPI receiver.

    // Parameters
    // [out]    data    Pointer to buffer for data to receive from SPI receiver
    // [in] num Number of data items to receive
    if (pDriver_SPI->Receive(data, bytesNumber) != ARM_DRIVER_OK)
    {
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return (0);
    }
    return 1;
}

/*******************************************************************************
 * @brief Writes data to SPI.
 *
 * @param slaveDeviceId - The ID of the selected slave device.
 * @param data - Data represents the write buffer.
 * @param bytesNumber - Number of bytes to write.
 *
 * @return Number of written bytes.
*******************************************************************************/
unsigned char SPI_Write(unsigned char slaveDeviceId,
                        unsigned char* data,
                        unsigned char bytesNumber)
{
    if (pDriver_SPI->Send(data, bytesNumber) != ARM_DRIVER_OK)
    {
        printf("%s %d error!\r\n", __FUNCTION__, __LINE__);
        return (0);
    }


    return (bytesNumber);
}

unsigned char SPI_Transfer(unsigned char data)
{
    int32_t status;
    unsigned char data_out;
    data_out = data;
    unsigned char data_in;

    if (status = pDriver_SPI->Transfer(&data_out, &data_in, 1) != ARM_DRIVER_OK)
    {
        printf("%s %d error %#x!\r\n", __FUNCTION__, __LINE__, status);
        return (0);
    }


    return (data_in);
}
